package com.personal.dao.sqlgenerator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import com.personal.dao.bean.BaseModel;
import com.personal.dao.bean.Criteria;
import com.personal.dao.bean.Criteria.Criterion;
import com.personal.dao.configuration.Configuration;
import com.personal.dao.dialect.DaoDialect;
import com.personal.dao.exception.NoPrimaryKeyAnnotationException;
import com.personal.dao.metadata.DataBaseFieldMetadata;
import com.personal.dao.metadata.DataBaseTableMetadata;
import com.personal.dao.reflection.MetaObject;
import com.personal.dao.sql.BaseSql;
import com.personal.dao.util.DaoUtil;
import com.personal.dao.util.ThreeTuple;

/**
 * 基础的Sql生成器
 * 
 * @author cuibo
 *
 */
public abstract class BaseSqlGenerator<T extends BaseModel> implements SqlGenerator
{

	/** 主键 */
	protected Object primaryKey;

	/** 实体条件 */
	protected T params;

	/** 实体值 */
	protected T value;

	/** 方言 */
	protected DaoDialect dialect;

	/** 元数据 */
	protected DataBaseTableMetadata<T> metadata;

	// public BaseSqlGenerator()
	// {
	// super();
	// }

	public BaseSqlGenerator(Object primaryKey, DataBaseTableMetadata<T> metadata, DaoDialect dialect)
	{
		super();
		this.primaryKey = primaryKey;
		this.metadata = metadata;
		this.dialect = dialect;
	}

	public BaseSqlGenerator(T params, DataBaseTableMetadata<T> metadata, DaoDialect dialect)
	{
		super();
		this.params = params;
		this.metadata = metadata;
		this.dialect = dialect;
	}

	public BaseSqlGenerator(Object primaryKey, T value, DataBaseTableMetadata<T> metadata, DaoDialect dialect)
	{
		super();
		this.primaryKey = primaryKey;
		this.value = value;
		this.metadata = metadata;
		this.dialect = dialect;
	}

	public BaseSqlGenerator(T value, DataBaseTableMetadata<T> metadata)
	{
		super();
		this.value = value;
		this.metadata = metadata;
	}

	public BaseSqlGenerator(DataBaseTableMetadata<T> metadata)
	{
		this.metadata = metadata;
	}
	
	/**
	 * 生成查询的列
	 * 
	 * @return
	 */
	protected String generateQuery()
	{
		StringBuilder result = new StringBuilder();
		if (params.isDistinct())
		{
			result.append("distinct ");
		}
		if (DaoUtil.isEmpty(params.getQueryFieldNames()))
		{
			// 判断是否有大数据字段
			if (metadata.isHasBigData() && !params.isSelectBigData())
			{
				// 只查非大数据字段
				if (metadata.getPrimaryKey() != null)
				{
					result.append(metadata.getPrimaryKey().getColumnName()).append(",");
				}
				for (DataBaseFieldMetadata metadata : metadata.getFields())
				{
					if (metadata.isBigData())
					{
						continue;
					}
					result.append(metadata.getColumnName()).append(",");
				}
				result.deleteCharAt(result.length() - 1);
				return result.toString();
			}
			return "*";
		} else
		{
			for (String string : params.getQueryFieldNames())
			{
				result.append(string).append(",");
			}
			result.deleteCharAt(result.length() - 1);
			return result.toString();
		}
	}

	/**
	 * 生成condition的条件
	 * 
	 * @return
	 */
	protected BaseSql generateCondition()
	{
		// 其本身列是DataBaseField或者DataBasePrimaryKey，并且值不为空，则拼接成条件
		StringBuilder sql = new StringBuilder();
		List<Object> list = new ArrayList<Object>();
		// Bean 自带的条件
		appendBeanCondition(sql, list);
		// Criteria 条件
		appendCriteriaCondition(sql, list);
		if (sql.length() == 0)
		{
			return null;
		}
		return new BaseSql(sql.toString(), list);
	}

	protected void appendPageAndOrderby(StringBuilder sql)
	{
		if (!DaoUtil.isEmpty(params.getOrderByClause()))
		{
			sql.append(" order by ").append(params.getOrderByClause());
		}
		if (params.getStart() != null && params.getLimit() != null)
		{
			String local = sql.toString();
			sql.setLength(0);
			sql.append(dialect.makePagging(local, params.getStart(), params.getLimit()));
		}
	}

	/**
	 * 拼接Criteria 条件
	 * 
	 * @param sql
	 * @param list
	 */
	private void appendCriteriaCondition(StringBuilder sql, List<Object> list)
	{
		if (DaoUtil.isEmpty(params.getOredCriteria()))
		{
			return;
		}
		if (sql.length() != 0)
		{
			sql.insert(0, "( ").append(" )");
			sql.append(" and ");
		}
		boolean single = params.getOredCriteria().size() == 1;
		for (Criteria criteria : params.getOredCriteria())
		{
			if (DaoUtil.isEmpty(criteria.getCriteria()))
			{
				continue;
			}
			if (!single)
			{
				sql.append(" ( ");
			}
			for (Criterion criterion : criteria.getCriteria())
			{
				// 获取元数据
				DataBaseFieldMetadata fieldMetadata = null;
				if (criterion.getFieldName() != null)
				{
					fieldMetadata = metadata
							.getDataBaseFieldMetadataByFieldName(criterion.getFieldName().toLowerCase(Locale.ENGLISH));
				}
				// 如果传入的列没有对应的元数据，则直接取其传入的名称
				String columnName = fieldMetadata == null ? criterion.getFieldName() : fieldMetadata.getColumnName();
				switch (criterion.getType())
				{
				case 无值条件:
					sql.append(columnName).append(criterion.getOperator()).append(" and ");
					break;
				case 单值条件:
					sql.append(columnName).append(criterion.getOperator()).append(" ? and ");
					list.add(criterion.getValue());
					break;
				case 前后范围值条件:
					sql.append("(").append(columnName).append(criterion.getOperator()).append(" ? and ?) and ");
					list.add(criterion.getValue());
					list.add(criterion.getSecondValue());
					break;
				case 多个范围值条件:
					sql.append(columnName).append(criterion.getOperator()).append("(");
					Collection<?> col = (Collection<?>) criterion.getValue();
					for (Object object : col)
					{
						sql.append("?,");
						list.add(object);
					}
					sql.deleteCharAt(sql.length() - 1).append(") and ");
					break;
				case 自定义条件:
					sql.append("(").append(criterion.getOperator()).append(") and ");
					Object[] arr = (Object[]) criterion.getValue();
					if (!DaoUtil.isEmpty(arr))
					{
						Collections.addAll(list, arr);
					}
					break;
				default:
					break;
				}
			}
			// 删除最后的and
			sql.delete(sql.length() - 4, sql.length());
			if (!single)
			{
				sql.append(" ) or");
			}
		}
		if (!single)
		{
			// 删除最后的or
			sql.delete(sql.length() - 2, sql.length());
		}
	}

	/**
	 * Bean 自带的条件
	 * 
	 * @param sql
	 * @param list
	 */
	private void appendBeanCondition(StringBuilder sql, List<Object> list)
	{
		// 生成元Object
		MetaObject metaObject = Configuration.getInstance().newMetaObject(params);
		if (metadata.getPrimaryKey() != null)
		{
			Object value = metaObject.getValue(metadata.getPrimaryKey().getFieldName());
			if (value != null)
			{
				sql.append(metadata.getPrimaryKey().getColumnName()).append(" = ? and ");
				list.add(value);
			}
		}
		for (DataBaseFieldMetadata field : metadata.getFields())
		{
			Object value = metaObject.getValue(field.getFieldName());
			if (value != null)
			{
				ThreeTuple<String, Object, String> operate = field.getOperator().createOperate(field, value);
				sql.append(operate.getA()).append(" ? ").append(operate.getC()).append(" and ");
				list.add(operate.getB());
			}
		}
		// 如果条件不为空，则截取最后的and
		if (sql.length() > 0)
		{
			sql.delete(sql.length() - 4, sql.length());
		}
	}

	/**
	 * 生成value的值：加null
	 * 
	 * @param withPrimaryKey
	 *            主键是否带上
	 * @param selective
	 *            是否带有选择性的
	 * @return
	 */
	protected BaseSql generateValue(boolean withPrimaryKey, boolean selective)
	{
		MetaObject metaObject = Configuration.getInstance().newMetaObject(this.value);
		// 校验
		SqlValidator.validate(metadata, this.value, metaObject);
		// 其本身列是DataBaseField或者DataBasePrimaryKey，并且值不为空，则拼接成条件
		StringBuilder sql = new StringBuilder();
		List<Object> list = selective ? new ArrayList<Object>()
				: new ArrayList<Object>(metadata.getFields().size() + 1);
		if (withPrimaryKey && metadata.getPrimaryKey() != null)
		{
			Object value = metaObject.getValue(metadata.getPrimaryKey().getFieldName());
			if (value != null)
			{
				sql.append(metadata.getPrimaryKey().getColumnName()).append(" = ?,");
				list.add(value);
			}
		}
		for (DataBaseFieldMetadata field : metadata.getFields())
		{
			Object value = metaObject.getValue(field.getFieldName());
			if (!selective)
			{
				sql.append(field.getColumnName()).append(" = ?,");
				list.add(value);
			} else
			{
				if (value != null)
				{
					sql.append(field.getColumnName()).append(" = ?,");
					list.add(value);
				}
			}
		}
		if (sql.length() == 0)
		{
			return null;
		}
		// 如果值不为空，则截取最后的,
		sql.deleteCharAt(sql.length() - 1);
		return new BaseSql(sql.toString(), list);
	}

	protected void checkPrimaryKey()
	{
		if (metadata.getPrimaryKey() == null)
		{
			throw new NoPrimaryKeyAnnotationException(metadata.getClass() + "对应的主键配置伪空，不支持此方法的操作！");
		}
	}

	public Object getPrimaryKey()
	{
		return primaryKey;
	}

	public void setPrimaryKey(Object primaryKey)
	{
		this.primaryKey = primaryKey;
	}

	public T getParams()
	{
		return params;
	}

	public void setParams(T params)
	{
		this.params = params;
	}

	public T getValue()
	{
		return value;
	}

	public void setValue(T value)
	{
		this.value = value;
	}

	public DaoDialect getDialect()
	{
		return dialect;
	}

	public void setDialect(DaoDialect dialect)
	{
		this.dialect = dialect;
	}

}
